////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//         This file is distributed under the BSD 2-Clause open source license. See Licenses/License.txt for details.         //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_SCRIPTING_MEMORY_MANAGER_H__
#define __WN_SCRIPTING_MEMORY_MANAGER_H__
#ifdef _WN_MSVC
    #pragma warning(push)
    #pragma warning(disable: 4244) 
    #pragma warning(disable: 4152) 
    #pragma warning(disable: 4512) 
    #pragma warning(disable: 4245) 
    #pragma warning(disable: 4127) 
    #pragma warning(disable: 4244) 
    #pragma warning(disable: 4100) 
    #pragma warning(disable: 4245)
#endif

#include "llvm/ExecutionEngine/JITMemoryManager.h"
#ifdef _WN_MSVC
#pragma warning(pop)
#endif

#include "WNScripting/inc/WNScriptingEngine.h"

namespace WNScripting {
    class WNScriptingMemoryManager : public llvm::JITMemoryManager {
    private:
        llvm::JITMemoryManager* Base;
    public:
        WNScriptingMemoryManager(WNScriptingEngine& _engine) :
            mEngine(_engine),
            Base(llvm::JITMemoryManager::CreateDefaultMemManager()){
        }
        virtual void *getPointerToNamedFunction(const std::string &Name,
                                            bool) {
            return(mEngine.GetRegisteredFunction(Name.c_str()));
            //return Base->getPointerToNamedFunction(Name, AbortOnFailure);
        }
        virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                                           unsigned SectionID){
            return Base->allocateCodeSection(Size, Alignment, SectionID);
        }
        virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                                           unsigned SectionID, bool IsReadOnly){
            return(Base->allocateDataSection(Size, Alignment, SectionID, IsReadOnly));
        }
        virtual bool applyPermissions(std::string *ErrMsg = 0) {
            return(Base->applyPermissions(ErrMsg));
        }
        virtual void setMemoryWritable(){
            Base->setMemoryWritable();
        }
        virtual void setMemoryExecutable() {
            Base->setMemoryExecutable();
        }
        virtual void setPoisonMemory(bool poison) {
            Base->setPoisonMemory(poison);
        }
        virtual void AllocateGOT() {
            return Base->AllocateGOT();
        }
        virtual void deallocateFunctionBody(void *Body) {
            Base->deallocateFunctionBody(Body);
        }
        virtual bool isManagingGOT() const {
            return Base->isManagingGOT();
        }
        virtual uint8_t* getGOTBase() const {
            return Base->getGOTBase();
        }
        virtual uint8_t* startFunctionBody(const llvm::Function* F, uintptr_t &ActualSize) {
            return(Base->startFunctionBody(F, ActualSize));
        }
        virtual uint8_t* allocateStub(const llvm::GlobalValue* F, unsigned StubSize, unsigned Alignment) {
            return(Base->allocateStub(F, StubSize, Alignment));
        }
        virtual void endFunctionBody(const llvm::Function* F, uint8_t* FunctionStart, uint8_t* FunctionEnd) {
            return(Base->endFunctionBody(F, FunctionStart, FunctionEnd));
        }
        virtual uint8_t* allocateSpace(intptr_t Size, unsigned Alignment) {
            return(Base->allocateSpace(Size, Alignment));
        }
        virtual uint8_t* allocateGlobal(uintptr_t Size, unsigned Alignment) {
            return(Base->allocateGlobal(Size, Alignment));
        }
        virtual bool CheckInvariants(std::string& str) {
            return(Base->CheckInvariants(str));
        }
        virtual size_t GetDefaultCodeSlabSize() {
            return(Base->GetDefaultCodeSlabSize());
        }
        virtual size_t GetDefaultDataSlabSize() {
            return(Base->GetDefaultDataSlabSize());
        }
        virtual size_t GetDefaultStubSlabSize() {
            return(Base->GetDefaultStubSlabSize());
        }
        virtual unsigned GetNumCodeSlabs() {
            return(Base->GetNumCodeSlabs());
        }
        virtual unsigned GetNumDataSlabs() {
            return(Base->GetNumDataSlabs());
        }
        virtual unsigned GetNumStubSlabs() {
            return(Base->GetNumStubSlabs() );
        }
        virtual uint8_t* startExceptionTable(const llvm::Function* F,
                                       uintptr_t &ActualSize) {
                                           return(Base->startExceptionTable(F, ActualSize));
        }

        virtual void endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
                                 uint8_t *TableEnd, uint8_t* FrameRegister) {
                                     return(Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister));
        }
        virtual void deallocateExceptionTable(void *ET) {
            return(Base->deallocateExceptionTable(ET));
        }
    private:
        WNScriptingEngine& mEngine;
    }; 
}
#endif//__WN_SCRIPTING_MEMORY_MANAGER_H__